using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics.Contracts;
using Konst3d.Efficiency.IO;
using Konst3d.Efficiency.Suite;

/* LAYOUT:
 * sign /4b
 * version /4b
 * active /1b
 * type /4b
 * monitorID /int - 4b
 * nameID (index) /4b
 * descrID (index) /4b
 * created_year   /4b int
 * created_month  /1b byte
 * created_day    /1b byte
 * created_hour   /1b byte
 * created_minute /1b byte
 * reserved /400b
*/

namespace Konst3d.Efficiency.Suite.SparsedBinary
{
    internal class MonitorFile : BinaryFile
    {
        #region Constants

        private const uint SIGNATURE = 0x01010101;
        private const uint VERSION = 1;
        private const int OFFSET_SIGNATURE = 0;
        private const int OFFSET_VERSION = 4;
        private const int OFFSET_ACTIVE = 8;
        private const int OFFSET_TYPE = 9;
        private const int OFFSET_MONITOR_ID = 13;
        private const int OFFSET_NAME_ID = 17;
        private const int OFFSET_DESCR_ID = 21;
        private const int OFFSET_CREATED_YEAR = 25;

        #endregion // Constants

        #region Properties

        public MonitorType Type
        {
            get
            {
                return (MonitorType)_typeID;
            }
            set
            {
                _writer.Write((int)value, OFFSET_TYPE);
                _typeID = (int)value;
            }
        }

        public int MonitorID
        {
            get
            {
                return _monitorID;
            }
            set
            {
                _writer.Write(value, OFFSET_MONITOR_ID);
                _monitorID = value;
            }
        }

        public byte Active
        {
            get
            {
                return _active;
            }
            set
            {
                _writer.Write(value, OFFSET_ACTIVE);
                _active = value;
            }
        }

        public int NameID
        {
            get
            {
                return _titleID;
            }
            set
            {
                _writer.Write(value, OFFSET_NAME_ID);
                _titleID = value;
            }
        }

        public int DescriptionID
        {
            get
            {
                return _descrID;
            }
            set
            {
                _writer.Write(value, OFFSET_DESCR_ID);
                _descrID = value;
            }
        }

        public DateTime Created
        {
            get
            {
                return _created;
            }
            set
            {
                _writer.Write(value, OFFSET_CREATED_YEAR);
                _created = value;
            }
        }

        #endregion // Properties

        #region Create/Open Methods

        public static MonitorFile Create(string path, bool overwrite, int id, MonitorType type, int titleID, int descriptionID, DateTime created, byte active)
        {
            Contract.Requires(!String.IsNullOrEmpty(path));

            if (File.Exists(path) && !overwrite)
            {
                throw new IOException(String.Format("File \"{0}\" is already exists.", path));
            }

            FileStream stream = null;
            BinaryReader reader = null;
            BinaryWriter writer = null;

            try
            {
                stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
                reader = new BinaryReader(stream, Encoding.UTF8);
                writer = new BinaryWriter(stream, Encoding.UTF8);

                writer.Write(SIGNATURE);
                writer.Write(VERSION);
                writer.Write(active);
                writer.Write((int)type);
                writer.Write(id);
                writer.Write(titleID);
                writer.Write(descriptionID);
                writer.Write(created);
                writer.WriteBytes(0, 400);

                writer.Flush();
                writer.Seek(0, SeekOrigin.Begin);

                return new MonitorFile(stream, reader, writer);
            }
            catch
            {
                if (stream != null)
                {
                    stream.Dispose();
                }

                if (reader != null)
                {
                    reader.Dispose();
                }

                if (writer != null)
                {
                    writer.Dispose();
                }

                throw;
            }
        }

        public static MonitorFile Open(string path)
        {
            Contract.Requires(!String.IsNullOrEmpty(path));
            Contract.Requires(File.Exists(path));

            FileStream stream = null;
            BinaryReader reader = null;
            BinaryWriter writer = null;

            try
            {
                stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
                reader = new BinaryReader(stream, Encoding.UTF8);
                writer = new BinaryWriter(stream, Encoding.UTF8);

                return new MonitorFile(stream, reader, writer);
            }
            catch
            {
                if (stream != null)
                {
                    stream.Dispose();
                }

                if (reader != null)
                {
                    reader.Dispose();
                }

                if (writer != null)
                {
                    writer.Dispose();
                }

                throw;
            }
        }

        #endregion // Create/Open Methods

        #region Constructor

        private MonitorFile(FileStream stream, BinaryReader reader, BinaryWriter writer):
            base(stream, reader, writer, SIGNATURE, VERSION)
        {
            _active     = (byte)_reader.ReadByte();
            _typeID     = _reader.ReadInt32();
            _monitorID  = _reader.ReadInt32();
            _titleID    = _reader.ReadInt32();
            _descrID    = _reader.ReadInt32();
            _created    = _reader.ReadDateTime();
        }

        #endregion // Constructor

        #region Fields

        private int _monitorID;
        private byte _active;
        private int _titleID;
        private int _descrID;
        private int _typeID;
        private DateTime _created;

        #endregion // Fields
    }
}
